/* RMORPG - Socket.cpp 
   Copyright (c) 2007, Michael Borgmann <code@lechuck.de>
   This code is released under the GNU Public License (GPL)
 */

#include <iostream>
#include "Socket.h"

using namespace rmorpg;

// DNS Lookup
unsigned long Socket::DNSLookup(const char *name) {
	// DNS Lookup
	struct hostent *host;
	host = gethostbyname(name);

	// return host
	return *((unsigned long*)host->h_addr_list[0]);
}

// Default Constructor
Socket::Socket() : sock(-1) {}

// Default Destructor FIXME
Socket::~Socket() {
	// check for existing socket
	if (sock != -1) {

		// shutdown socket
		int result = shutdown(sock, 2);

		// check for errors
		if (result == -1) exit(0);

		// close socket
		result = close(sock);

		// check for errors
		if (result == -1) exit(0);
	}
}

// Create TCP Socket
bool Socket::CreateTCPSocket() {
	// create socket
	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	// check for errors
	if (sock == -1) return false;

	return true;
}

// Create UDP Socket
bool Socket::CreateUDPSocket() {
	// create socket
	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);

	// check for errors
	if (sock == -1) return false;

	return true;
}

// Bind Socket
bool Socket::Bind(const int port, char *addr) {
	// sockaddr_in structure to bind socket
	socketaddress.sin_family = AF_INET;
	socketaddress.sin_port = htons(port);
	if (!addr) socketaddress.sin_addr.s_addr = htonl(INADDR_ANY);
	else socketaddress.sin_addr.s_addr = DNSLookup(addr);
	// memset(&(socketaddress.sin_zero), 0, 8);

	// bind socket
	int result = bind(sock, (sockaddr*)&socketaddress, sizeof(sockaddr));

	// check for errors
	if (sock == -1) return false;

	return true;
}

// Listen to Socket
bool Socket::Listen(const int max_connections) {
	// listen to socket
	int result = listen(sock, max_connections);

	// check for errors
	if (sock == -1) return false;

	return true;
}

// Accept Client
bool Socket::Accept(Socket &new_socket) {
	// accept new socket connection
	socklen_t sa_size = sizeof(sockaddr_in);
	new_socket.sock = accept(sock, (sockaddr*)&socketaddress, &sa_size);

	// check for errors
	if (new_socket.sock == -1) return false;

	return true;
}

// Connect to Server
bool Socket::Connect(const char *host, int port) {
	socketaddress.sin_family = AF_INET;
	socketaddress.sin_port = htons(port);
	socketaddress.sin_addr.s_addr = DNSLookup(host);
	// memset(&(socketaddress.sin_zero), 0, 8);

	int result = connect(sock, (sockaddr*)&socketaddress, sizeof(sockaddr));

	// check for errors
	if (result == -1) return false;

	return true;
}

// Send Packet
bool Socket::Send(char *packet, int size) {
	// send packet
	int bytes = send(sock, packet, size, 0);

	// check for errors
	if (bytes == -1) return false;

	return true;
}

// Receive Packet
bool Socket::Receive(char *buffer, int size) {
	// receive packet
	int bytes = recv(sock, buffer, size, 0);

	// check for errors
	if (bytes == -1) return false;

	return true;
}

// Get Socket
int Socket::Get() {
	return sock;
}

// Set Socket
int Socket::Set(int s) {
	return sock = s;
}
